package umich.infinity.facebookconn;
/**
 * #############################################################################
 * #
 * 
 * DOCOMO Innovations, Inc.
 * 
 * Copyright © 2011 DOCOMO Innovations, Inc. All rights reserved.
 * 
 * 
 * 
 * Date of Preparation: 08/01/2011
 * 
 * Contact: kozat@docomoinnovations.com
 * 
 * 
 * 
 * All intellectual property rights related to this software are vested in
 * DOCOMO Innovations.
 * 
 * DOCOMO Innovations is under no obligation to maintain or support the
 * software.
 * 
 * Neither DOCOMO Innovations nor its employees are responsible for any damage
 * or loss resulting from the use of the software.
 * 
 * #############################################################################
 * #
 */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import org.apache.thrift.TException;
import org.apache.thrift.TProcessor;
import org.apache.thrift.TProcessorFactory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransport;
import org.json.*;

import umich.infinity.proxy.Para;
import umich.infinity.thrift.Aggregator.Iface;
import umich.infinity.thrift.Aggregator.Processor;
import umich.infinity.thrift.*;


public class FacebookConn {

	// Strings used in the authorization flow
	public static final String REDIRECT_URI = "fbconnect://success";
	public static final String CANCEL_URI = "fbconnect://cancel";
	public static final String TOKEN = "access_token";
	public static final String EXPIRES = "expires_in";
	public static final String SINGLE_SIGN_ON_DISABLED = "service_disabled";

	public static final int FORCE_DIALOG_AUTH = -1;

	private static final String LOGIN = "oauth";

	// Used as default activityCode by authorize(). See authorize() below.
	private static final int DEFAULT_AUTH_ACTIVITY_CODE = 32665;

	// Facebook server endpoints: may be modified in a subclass for testing
	protected static String DIALOG_BASE_URL =
			"https://m.facebook.com/dialog/";
	protected static String GRAPH_BASE_URL =
			"https://graph.facebook.com/";
	protected static String RESTSERVER_URL =
			"https://api.facebook.com/restserver.php";

	private String mAccessToken = null;
	private long mAccessExpires = 0;
	private String mAppId;

	/**
	 * Constructor for Facebook object.
	 *
	 * @param appId
	 *          Your Facebook application ID. Found at
	 *          www.facebook.com/developers/apps.php.
	 */
	public FacebookConn(String appId) {
		if (appId == null) {
			throw new IllegalArgumentException(
					"You must specify your application ID when instantiating " +
					"a Facebook object. See README for details.");
		}
		mAppId = appId;
	}

	public void setAccessToken(String accessToken, long accessExpires) {
		mAccessToken  = accessToken;
		mAccessExpires = accessExpires;
	}
	
	
	public String batchRequest(Bundle parameters)
			throws FileNotFoundException, MalformedURLException, IOException {
		
		return request(null, parameters, "POST");
	}
	/**
	 * Make a request to Facebook's old (pre-graph) API with the given
	 * parameters. One of the parameter keys must be "method" and its value
	 * should be a valid REST server API method.
	 *
	 * See http://developers.facebook.com/docs/reference/rest/
	 *
	 * Note that this method blocks waiting for a network response, so do not
	 * call it in a UI thread.
	 *
	 * Example:
	 * <code>
	 *  Bundle parameters = new Bundle();
	 *  parameters.putString("method", "auth.expireSession");
	 *  String response = request(parameters);
	 * </code>
	 *
	 * @param parameters
	 *            Key-value pairs of parameters to the request. Refer to the
	 *            documentation: one of the parameters must be "method".
	 * @throws IOException
	 *            if a network error occurs
	 * @throws MalformedURLException
	 *            if accessing an invalid endpoint
	 * @throws IllegalArgumentException
	 *            if one of the parameters is not "method"
	 * @return JSON string representation of the response
	 */
	public String request(Bundle parameters)
			throws MalformedURLException, IOException {
		if (!parameters.containsKey("method")) {
			throw new IllegalArgumentException("API method must be specified. "
					+ "(parameters must contain key \"method\" and value). See"
					+ " http://developers.facebook.com/docs/reference/rest/");
		}
		return request(null, parameters, "GET");
	}

	/**
	 * Make a request to the Facebook Graph API without any parameters.
	 *
	 * See http://developers.facebook.com/docs/api
	 *
	 * Note that this method blocks waiting for a network response, so do not
	 * call it in a UI thread.
	 *
	 * @param graphPath
	 *            Path to resource in the Facebook graph, e.g., to fetch data
	 *            about the currently logged authenticated user, provide "me",
	 *            which will fetch http://graph.facebook.com/me
	 * @throws IOException
	 * @throws MalformedURLException
	 * @return JSON string representation of the response
	 */
	public String request(String graphPath)
			throws MalformedURLException, IOException {
		return request(graphPath, new Bundle(), "GET");
	}

	/**
	 * Make a request to the Facebook Graph API with the given string parameters
	 * using an HTTP GET (default method).
	 *
	 * See http://developers.facebook.com/docs/api
	 *
	 * Note that this method blocks waiting for a network response, so do not
	 * call it in a UI thread.
	 *
	 * @param graphPath
	 *            Path to resource in the Facebook graph, e.g., to fetch data
	 *            about the currently logged authenticated user, provide "me",
	 *            which will fetch http://graph.facebook.com/me
	 * @param parameters
	 *            key-value string parameters, e.g. the path "search" with
	 *            parameters "q" : "facebook" would produce a query for the
	 *            following graph resource:
	 *            https://graph.facebook.com/search?q=facebook
	 * @throws IOException
	 * @throws MalformedURLException
	 * @return JSON string representation of the response
	 */
	public String request(String graphPath, Bundle parameters)
			throws MalformedURLException, IOException {
		return request(graphPath, parameters, "GET");
	}

	/**
	 * Synchronously make a request to the Facebook Graph API with the given
	 * HTTP method and string parameters. Note that binary data parameters
	 * (e.g. pictures) are not yet supported by this helper function.
	 *
	 * See http://developers.facebook.com/docs/api
	 *
	 * Note that this method blocks waiting for a network response, so do not
	 * call it in a UI thread.
	 *
	 * @param graphPath
	 *            Path to resource in the Facebook graph, e.g., to fetch data
	 *            about the currently logged authenticated user, provide "me",
	 *            which will fetch http://graph.facebook.com/me
	 * @param params
	 *            Key-value string parameters, e.g. the path "search" with
	 *            parameters {"q" : "facebook"} would produce a query for the
	 *            following graph resource:
	 *            https://graph.facebook.com/search?q=facebook
	 * @param httpMethod
	 *            http verb, e.g. "GET", "POST", "DELETE"
	 * @throws IOException
	 * @throws MalformedURLException
	 * @return JSON string representation of the response
	 */
	public String request(String graphPath, Bundle params, String httpMethod)
			throws FileNotFoundException, MalformedURLException, IOException {
		params.putString("format", "json");
		if (isSessionValid()) {
			params.putString(TOKEN, getAccessToken());
		}
		String url = (graphPath != null) ? GRAPH_BASE_URL + graphPath
				: RESTSERVER_URL;
		return FacebookUtil.openUrl(url, httpMethod, params);
	}

	/**
	 * @return boolean - whether this object has an non-expired session token
	 */
	public boolean isSessionValid() {
		return (getAccessToken() != null) &&
				((getAccessExpires() == 0) ||
						(System.currentTimeMillis() < getAccessExpires()));
	}

	/**
	 * Retrieve the OAuth 2.0 access token for API access: treat with care.
	 * Returns null if no session exists.
	 *   
	 * @return String - access token
	 */
	public String getAccessToken() {
		return mAccessToken;
	}

	/**
	 * Retrieve the current session's expiration time (in milliseconds since
	 * Unix epoch), or 0 if the session doesn't expire or doesn't exist.
	 *
	 * @return long - session expiration time
	 */
	public long getAccessExpires() {
		return mAccessExpires;
	}

	/**
	 * Invalidate the current user session by removing the access token in
	 * memory, clearing the browser cookie, and calling auth.expireSession
	 * through the API.
	 *
	 * Note that this method blocks waiting for a network response, so do not
	 * call it in a UI thread.
	 *
	 * @param context
	 *            The Android context in which the logout should be called: it
	 *            should be the same context in which the login occurred in
	 *            order to clear any stored cookies
	 * @throws IOException
	 * @throws MalformedURLException
	 * @return JSON string representation of the auth.expireSession response
	 *            ("true" if successful)
	 */
	public String logout(Context context)
			throws MalformedURLException, IOException {
		FacebookUtil.clearCookies(context);
		Bundle b = new Bundle();
		b.putString("method", "auth.expireSession");
		String response = request(b);
		setAccessToken(null);
		setAccessExpires(0);
		return response;
	}

	/**
	 * Set the OAuth 2.0 access token for API access.
	 *
	 * @param token
	 *            - access token
	 */
	public void setAccessToken(String token) {
		mAccessToken = token;
	}

	/**
	 * Set the current session's expiration time (in milliseconds since Unix
	 * epoch), or 0 if the session doesn't expire.
	 *
	 * @param time
	 *            - timestamp in milliseconds
	 */
	public void setAccessExpires(long time) {
		mAccessExpires = time;
	}

	public class SampleAlbumsListener extends BaseRequestListener {

		public void onComplete(final String response, final Object state) {
			try {
				// process the response here: executed in background thread
				JSONObject json = FacebookUtil.parseJson(response);
				JSONArray data = json.getJSONArray("data");
				System.out.println(response);                
				for (int i=0; i<data.length(); i++) {
					JSONObject obj = data.getJSONObject(i);

					String id = obj.getString("id");
					String name = obj.getString("name");

					if (name.compareTo("exp") == 0) {

						AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(FacebookConn.this);
						System.out.println ("Start photo request...");
						mAsyncRunner.request(id+"/photos", new BaseRequestListener() {
							@Override
							public void onComplete(final String response, final Object state) {        	            	 
								try {
									JSONObject json = FacebookUtil.parseJson(response);
									JSONArray data = json.getJSONArray("data");
									for (int i=0; i<data.length(); i++) {
										JSONObject obj = data.getJSONObject(i);

										String id = obj.getString("id");
										String source = obj.getString("source");

										/*
					                	InputStream pData = Util.openUrlBin(source, "GET", new Bundle() {});

					                	BufferedInputStream in = new BufferedInputStream(pData);

					                	FileOutputStream file = new FileOutputStream("/home/stgyd/"+id+".jpg");

					                	BufferedOutputStream out = new BufferedOutputStream(file);
					                	int ii;
					                	while ((ii = in.read()) != -1) {
					                	    out.write(ii);
					                	}
					                	out.flush();

					                	out.close();
										 */
										ByteBuffer pData = FacebookUtil.readBin(FacebookUtil.openUrlBin(source, "GET", new Bundle() {}));

										FileOutputStream file = new FileOutputStream(Para.CacheRoot+id+".jpg");

										BufferedOutputStream out = new BufferedOutputStream(file);
										out.write(pData.array());

										out.flush();

										out.close();

										System.out.println ("" + i + " " + id + " " + source);
									}
								} catch (JSONException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (FacebookError e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (MalformedURLException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								} catch (IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						}
								);
					}

				}
			} catch (FacebookError e) {
				e.printStackTrace();
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void action() {   	
		AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(this);
		System.out.println ("Start album request...");
		mAsyncRunner.request("me/albums", new SampleAlbumsListener());		
	}

}
